package game;

import java.io.IOException;
import java.util.Map;

/**
 * Player describes the behaviour of user who wants to play {@link Game}
 * 
 * @author Tsvetan Vasilev
 * 
 */
public class Player implements Runnable {

	// specific player's fields
	private Integer id;
	private String name;
	private PlayerIOManager playerIOManager;

	// monitors
	private Game game;
	private PlayersManager playersManager;

	// --- Constructors,Getters,Setters ----------------------------------------
	public Player(Integer id, String name, PlayerIOManager playerIOManager,
			PlayersManager playersManager) {
		this.id = id;
		this.name = name;
		this.playerIOManager = playerIOManager;
		this.playersManager = playersManager;
	}

	public Game getGame() {
		return game;
	}

	public void setGame(Game game) {
		this.game = game;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public PlayersManager getPlayresManager() {
		return playersManager;
	}

	public PlayerIOManager getPlayerIOManager() {
		return playerIOManager;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	// --- Methods -------------------------------------------------------------

	@Override
	public void run() {
		try {
			// enter player's name
			name = playerIOManager.getPlayerName();

			boolean playerWantToPlay = true;
			do {

				// 1.
				initiateGame();

				// 2.
				playGame();

				// 3. Finish or StartNewGame
				playerWantToPlay = playerIOManager.askForNewGame();

			} while (playerIOManager.isConnected() && playerWantToPlay);
		} catch (Exception e) {
			e.printStackTrace();
			game.setPlayersFree();
		} finally {
			try {
				disconnect();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		System.out.println(Thread.currentThread().getName() + "run() END");
	}

	// --- Auxiliary Methods ---------------------------------------------------

	private void disconnect() throws IOException {
		playerIOManager.closeConnection();
		playersManager.deletePlayer(this);
	}

	private void initiateGame() throws IOException, InterruptedException {
		while (game == null) {
			// offer players
			Map<Integer, String> id2NamesFreePlayers = playersManager
					.getId2NamesFreePlayers();
			playerIOManager.offerPlayers(id2NamesFreePlayers);

			// choose opponent
			boolean hasGameStarted = false;
			do {
				// 1) get chosen index ->
				int chosenIndex = playerIOManager.chooseOpponentPlayerIndex(
						this, id2NamesFreePlayers.size());
				if (chosenIndex == 0) {
					playersManager.superviseWaitingPlayer(this);

					// I'm not in freePlayersMap (somebody chose me).
					// So break from while-statement and playGame()
					break;
				} else {// chosenIndex!=0
					hasGameStarted = playersManager.createGame(this,
							chosenIndex);
				}
			} while (!hasGameStarted);
		}
	}

	private void playGame() throws InterruptedException, IOException {
		// notify for starting game
		playerIOManager.notifyForGameStart(this.getName(),
				game.getOpponent(this).getName());

		// choose secret number
		String secretNumber = getPlayerIOManager().chooseSecretNumber();
		game.chooseSecretNumber(this, secretNumber);

		while (!game.isOver()) {
			game.playTurn(this);
		}
		game.announceWinner(this);

		game.setPlayersFree();
		setGame(null);

	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Player)) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		Player player = (Player) obj;
		return name.equals(player.getName());
	}
}
